package com.inter.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * HmacSHA1签名
 *
 * @author lm
 * @date 2020/10/29 16:29
 */
@Component
public class HMACSHA1 {
    private static Logger logger = Logger.getLogger(HMACSHA1.class);

    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";

    /**
     * 计算返回报文签名 for json
     */
    public static String jsonSign(Object obj, String key) {
        Map<String, Object> map = objectToMap(obj);
        //去掉添加的签名字段
        map.remove("sign");
        map = sortMapByKey(map);
        String headJson = JSON.toJSONString(map);
        String sign = generateSign(headJson, key);
        /*logger.info("请求网关签名体：" + headJson + ";签名：" + sign);*/
        return sign;
    }

    /**
     * 对传入的object进行数据清洗，将属性值为null和""的去掉，其他字段名和属性值存入map集合并返回
     */
    public static Map<String, Object> objectToMap(Object requestParameters) {

        //这边map的集合value用泛型（String和Integer都可以接受）
        Map<String, Object> map = new HashMap<String, Object>(16);

        try {
            // 获取f对象对应类中的所有属性域
            Field[] fields = requestParameters.getClass().getDeclaredFields();
            for (int i = 0, len = fields.length; i < len; i++) {
                String varName = fields[i].getName();
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o = fields[i].get(requestParameters);
                if (o != null && StringUtils.isNotBlank(o.toString().trim())) {
                    map.put(varName, o);
                    // 恢复访问控制权限
                    fields[i].setAccessible(accessFlag);
                }
            }
        } catch (Exception e) {
            logger.info("map转换有误：" + e);
        }
        return map;
    }

    /**
     * 将map集合按照key的自然顺序进行排序
     *
     * @param map
     * @return
     */
    public static Map<String, Object> sortMapByKey(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, Object> sortMap = new TreeMap<String, Object>(new MapKeyComparator());
        sortMap.putAll(map);
        return sortMap;
    }


    /**
     * 使用HmacSHA1计算签名
     * <p>
     * 1.8jdk以上写法java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();return encoder.encodeToString(res);
     *
     * @param data
     * @param secretKey
     * @return
     */
    public static String generateSign(String data, String secretKey) {
        try {
            SecretKeySpec sk = new SecretKeySpec(secretKey.getBytes("UTF-8"), MAC_NAME);
            Mac mac = Mac.getInstance(MAC_NAME);
            mac.init(sk);
            byte[] res = mac.doFinal(data.getBytes(ENCODING));
            return new sun.misc.BASE64Encoder().encode(res);
        } catch (Exception e) {
            logger.info("HmacSHA1签名异常：" + e);
            return null;
        }

    }
}
